"use strict";
!function(win){
	var doc = window.document
	var config = {
		modules:{},
		css:{},
		widgets:{},
		status:{},
		timeout:10,
		event:{}
	}
	var error = function(message){
		console.error(message);
	}
	// 存储模块的回调
	config.callback = {};
	var modules = config.builtin ={
		'all':'all'
	}
	var css = {};
	// 识别预先可能定义的指定全局对象
	var GLOBAL = win.WED_GLOBAL || {};
	var isOpera = typeof opera !== 'undefined' && opera.toString() === '[object Opera]';

	var WebEditor = function(){
		this.v = '2.0.0';	
	}
	// 记录基础数据
	WebEditor.prototype.cache = config;
	WebEditor.prototype.css = css;
  	// 全局配置
	WebEditor.prototype.config = function(options){
		options = options || {};
		for(var key in options){
			config[key] = options[key];
		}
		return this;
	};
	WebEditor.prototype.initModules = async function(){
		var that = this;
		if(config.css){
			for(var item in config.css){
				if(!that.css[item]){
					var url = config.baseUrl + '/' + config.css[item] + '.css';
					await that.loadCss(url);
					that.css[item] = config.css[item];
				}
			}
		}
		if(config.modules){
			for(var item in config.modules){
				if(!that.modules[item]){
					var url = config.baseUrl + '/' + config.modules[item] + '.js';
					await that.loadJSModule(url);
					that.modules[item] = config.modules[item];
				}
			}
		}
		if(config.widgets){
			for(var item in config.widgets){
				if(!that.modules[item]){
					var url = config.baseUrl + '/' + config.widgets[item] + '.js';
					await that.loadJSModule(url);
					that.modules[item] = config.widgets[item];
				}
			}
		}
	}
	// 定义模块
	WebEditor.prototype.define = function(deps, factory){
		var that = this;
		var type = typeof deps === 'function';
		var callback = function(){
			var setApp = function(app, exports){
				webEditor[app] = exports;
				config.status[app] = true;
			};
			typeof factory === 'function' && factory(function(app, exports){
				setApp(app, exports);
				config.callback[app] = function(){
					factory(setApp);
				}
			});
			return this;
		};

		type && (
			factory = deps,
			deps = []
			);

		that.use(deps, callback, null, 'define');
		return that;
	};

	// 重新执行模块的工厂函数
	WebEditor.prototype.factory = function(modName){
		if(webEditor[modName]){
			return typeof config.callback[modName] === 'function'
			? config.callback[modName]
			: null;
		}
	};

	// 记录全部模块
	WebEditor.prototype.modules = function(){
		var clone = {};
		for(var o in modules){
			clone[o] = modules[o];
		}
		return clone;
	}();

	// 弃用原有的指定模块，以便重新扩展新的同名模块
	WebEditor.prototype.disuse = function(apps){
		var that = this;
		apps = that.isArray(apps) ? apps : [apps];
		that.each(apps, function (index, item) {
			if (!config.status[item]) {
        // return error('module ' + item + ' is not exist');
			}
			delete that[item];
			delete modules[item];
			delete that.modules[item];
			delete config.status[item];
			delete config.modules[item];
		});
		return that;
	};
	// typeof 类型细分 -> string/number/boolean/undefined/null、object/array/function/…
	WebEditor.prototype._typeof = WebEditor.prototype.type = function(operand){
		if(operand === null) return String(operand);

	    // 细分引用类型
		return (typeof operand === 'object' || typeof operand === 'function') ? function(){
	      var type = Object.prototype.toString.call(operand).match(/\s(.+)\]$/) || []; // 匹配类型字符
	      var classType = 'Function|Array|Date|RegExp|Object|Error|Symbol'; // 常见类型字符

	      type = type[1] || 'Object';

	      // 除匹配到的类型外，其他对象均返回 object
	      return new RegExp('\\b('+ classType + ')\\b').test(type)
	      ? type.toLowerCase()
	      : 'object';
	  }() : typeof operand;
	};
	
	// 使用特定模块
	WebEditor.prototype.use = function(apps, callback, exports, from){
		var that = this;
		var dir = config.dir = config.dir ? config.dir : '';
		var head = doc.getElementsByTagName('head')[0];
		apps = function(){
			if(typeof apps === 'string'){
				return [apps];
			}
      		// 当第一个参数为 function 时，则自动加载所有内置模块，且执行的回调即为该 function 参数；
			else if(typeof apps === 'function'){
				callback = apps;
				return ['all'];
			}
			return apps;
		}();
		var item = apps[0];
		var timeout = 0;

		exports = exports || [];

    	// 静态资源host
		config.host = config.host || (dir.match(/\/\/([\s\S]+?)\//)||['//'+ location.host +'/'])[0];

    	// 加载完毕
		function onScriptLoad(e, url){
			var readyRegExp = navigator.platform === 'PLaySTATION 3' ? /^complete$/ : /^(complete|loaded)$/
			if (e.type === 'load' || (readyRegExp.test((e.currentTarget || e.srcElement).readyState))) {
				config.modules[item] = url;
				head.removeChild(node);
				(function poll() {
					if(++timeout > config.timeout * 1000 / 4){
						return error(item + ' is not a valid module', 'error');
					}
					config.status[item] ? onCallback() : setTimeout(poll, 4);
				}());
			}
		}

    	// 回调
		function onCallback(){
			exports.push(webEditor[item]);
			apps.length > 1 ?
			that.use(apps.slice(1), callback, exports, from)
			: ( typeof callback === 'function' && function(){
        		// 保证文档加载完毕再执行回调
				callback.apply(webEditor, exports);
			}() );
		}

    	// 如果引入了聚合板，内置的模块则不必重复加载
		if( apps.length === 0 || modules[item] ){
			return onCallback(), that;
		}
		var url = ( modules[item] ? (dir + 'modules/')
			: (/^\{\/\}/.test(that.modules[item]) ? '' : (config.base || ''))
			) + (that.modules[item] || item) + '.js';
		url = url.replace(/^\{\/\}/, '');
	    // 如果扩展模块（即：非内置模块）对象已经存在，则不必再加载
		if(!config.modules[item] && webEditor[item]){
	      config.modules[item] = url; // 并记录起该扩展模块的 url
	  }
    	// 首次加载模块
	  if(!config.modules[item]){
	  	var node = doc.createElement('script');
	  	node.async = true;
	  	node.charset = 'utf-8';
	  	node.src = url + function(){
	  		var version = config.version === true
	  		? (config.v || (new Date()).getTime())
	  		: (config.version||'');
	  		return version ? ('?v=' + version) : '';
	  	}();

	  	head.appendChild(node);

	  	if(node.attachEvent && !(node.attachEvent.toString && node.attachEvent.toString().indexOf('[native code') < 0) && !isOpera){
	  		node.attachEvent('onreadystatechange', function(e){
	  			onScriptLoad(e, url);
	  		});
	  	} else {
	  		node.addEventListener('load', function(e){
	  			onScriptLoad(e, url);
	  		}, false);
	  	}

	  	config.modules[item] = url;
    	} else { // 缓存
    		(function poll() {
    			if(++timeout > config.timeout * 1000 / 4){
    				return error(item + ' is not a valid module', 'error');
    			}
    			(typeof config.modules[item] === 'string' && config.status[item])
    			? onCallback()
    			: setTimeout(poll, 4);
    		}());
    	}

    	return that;
    };
    WebEditor.prototype.poll = function(condition, onCallback){
    	var timeout = 10;
 		(function poll() {
 			if(++timeout > config.timeout * 1000 / 4){
				return error('widgets is not a valid', 'error');
			}
			condition ? onCallback() : setTimeout(poll, 4);
		}());
    }
 	WebEditor.prototype.widgetsDone = function(onCallback){
 		
 		var timeout = 10;
 		(function poll() {
 			if(++timeout > config.timeout * 1000 / 4){
				return error('widgets is not a valid', 'error');
			}
 			// console.log(Object.keys(config.widgets).length);
 			// console.log(Object.keys(MyModules.status).length);
 			var allDone = Object.keys(config.widgets).length == Object.keys(MyModules.status).length;
 		
			allDone ? onCallback() : setTimeout(poll, 4);
		}());
 	}
    // 动态加载js
    WebEditor.prototype.loadJSModule = function(moduleURL) {
		var head = doc.getElementsByTagName('head')[0];
    	// 加载完毕
		function onScriptLoad(e, url, node){
			var readyRegExp = navigator.platform === 'PLaySTATION 3' ? /^complete$/ : /^(complete|loaded)$/
			if (e.type === 'load' || (readyRegExp.test((e.currentTarget || e.srcElement).readyState))) {
				head.removeChild(node);				
			}
		}

    	return new Promise((resolve, reject) => {
    		var script = document.createElement('script');
    		script.type = 'text/javascript';
    		script.src = moduleURL;

		    script.onload = () => resolve(moduleURL);  // 模块加载完成
		    script.onerror = () => reject(new Error(`Failed to load module: ${moduleURL}`));  // 模块加载失败

		    head.appendChild(script);

		    if(script.attachEvent && !(script.attachEvent.toString && script.attachEvent.toString().indexOf('[native code') < 0) && !isOpera){
	      		script.attachEvent('onreadystatechange', function(e){
	      			onScriptLoad(e, moduleURL, script);
	      		});
	      	} else {
	      		script.addEventListener('load', function(e){
	      			onScriptLoad(e, moduleURL, script);
	      		}, false);
	      	}
		});
    }
    WebEditor.prototype.loadCss = function(url){
    	var link = document.createElement('link');
        link.type = 'text/css';
        link.rel = 'stylesheet';
        link.href = url;
        document.getElementsByTagName('head')[0].appendChild(link);
    }
    // 阻止事件冒泡
    WebEditor.prototype.stope = function(thisEvent){
    	thisEvent = thisEvent || win.event;
    	try { thisEvent.stopPropagation() } catch(e){
    		thisEvent.cancelBubble = true;
    	}
    };
    // 防抖
    WebEditor.prototype.debounce = function (func, wait) {
    	var timeout;
    	return function () {
    		var context = this;
    		var args = arguments;
    		clearTimeout(timeout);
    		timeout = setTimeout(function () {
    			func.apply(context, args);
    		}, wait);
    	}
    };
    // 节流
    WebEditor.prototype.throttle = function (func, wait) {
    	var cooldown = false;
    	return function () {
    		var context = this;
    		var args = arguments;
    		if (!cooldown) {
    			func.apply(context, args);
    			cooldown = true;
    			setTimeout(function () {
    				cooldown = false;
    			}, wait);
    		}
    	}
    };
    
    window.webEditor = new WebEditor();
}(window);